#include "titanfall2/ViewProjectionMatrix.h"
#include <sigscanner/ModuleScanner.h>
#include <format>
#include <stdexcept>

static const char* viewProjectionMatrixSignature = 
"48 8D 0D ? ? ? ? E8 ? ? ? ? 48 8D 0D ? ? ? ? 48 83 C4 28 E9 ?"
" ? ? ? 48 8D 0D ? ? ? ? E9 ? ? ? ? CC CC CC CC 48 83 EC 28 48"
" 8D 0D";

[[nodiscard]]
float* GetViewProjectionMatrixPtr()
{
    const auto scanResult = signature_scanner::ModuleScanner("client.dll").FindPattern(viewProjectionMatrixSignature);

    if (!scanResult.has_value())
        throw std::runtime_error(std::format("Failed to find view-projection matrix! Pattern: '{}'",
                                             viewProjectionMatrixSignature));

    const auto offsetToList = *(uint32_t*)(scanResult.value()+3);
    return reinterpret_cast<float*>(scanResult.value()+offsetToList+7);
}
namespace titanfall2
{
    omath::matrix GetViewProjectionMatrix()
    {
        static auto ptr = GetViewProjectionMatrixPtr();

        return {4, 4, ptr};
    }
    std::optional<omath::Vector3> WorldToScreen(omath::Vector3 worldPosition, float width, float height)
    {
        auto projected = (GetViewProjectionMatrix() * worldPosition).transpose();

        projected /= projected.at(0, 3);

        const auto out = projected * omath::matrix::to_screen_matrix(width,
                                                                    height);

        if (out.at(0,2) <= 0.f)
            return std::nullopt;
        
        auto final = omath::Vector3(out.at(0,0),
                                    out.at(0, 1),
                                    out.at(0,2));
        return {final};
        
    }
}